#include <iostream>
#include <string>
#include <vector>
#include <cerrno>
#include <boost/filesystem.hpp>
#include <cstring>
#include <boost/filesystem.hpp>
#include "util.hpp"

// 放html网页
const std::string src_path = "data/input"; // 前置路径
const std::string output = "data/raw_html/raw.txt";

typedef struct DocInfo
{
  std::string title;   // 文档的标题
  std::string content; // 文档的内容 --body里面有内容信息
  std::string url;     // 该文档在官网中的url
} DocInfo_t;

bool EnumFile(const std::string &src_path, std::vector<std::string> *files_list);
bool ParseHtml(const std::vector<std::string> &files_list, std::vector<DocInfo_t> *results);
bool SaveHtml(const std::vector<DocInfo_t> &results, const std::string &output);

int main()
{
  std::vector<std::string> files_list;

  // 1.递归式的把每个html文件命带路径,保存到files_list中
  // 方便后期进行一个一个文件的读取
  if (!EnumFile(src_path, &files_list))
  {
    std::cerr << "euum file name error!" << std::endl;
    return 1;
  }

  // 2.按照files_list 读取每个文件的内容,并进行解析
  std::vector<DocInfo_t> results; // 解析后的结果存放在results中
  if (!ParseHtml(files_list, &results))
  {
    std::cerr << "parse html error" << std::endl;
    return 2;
  }

  // 3.把解析完毕的各个文件内容,写入到output中,按照\3作为分隔符
  if (!SaveHtml(results, output))
  {
    std::cerr << "sava html error" << std::endl;
    return 3;
  }

  return 0;
}

bool EnumFile(const std::string &src_path, std::vector<std::string> *files_list)
{
  namespace fs = boost::filesystem; // 给命名空间起别名
  fs::path root_path(src_path);
  if (!fs::exists(root_path)) // 路径不存在直接退出
  {
    std::cerr << src_path << "not exists" << std::endl;
    return false;
  }

  // 定义一个迭代器来判断递归的结束
  fs::recursive_directory_iterator end;
  // 遍历文件路径
  for (fs::recursive_directory_iterator iter(root_path); iter != end; iter++)
  {
    // 判断是不是普通文件
    if (!fs::is_regular_file(*iter))
    {
      continue;
    }
    // 判断文件名的后缀是否符合要求
    if (iter->path().extension() != ".html")
    {
      continue;
    }
    files_list->push_back(iter->path().string()); // 把带路径的html保存在files_list中
  }

  return true;
}

//  <title> xxxxxxxxxxxxxxxx </title>
static bool ParseTitle(const std::string &file, std::string *title)
{
  std::size_t begin = file.find("<title>");
  if (begin == std::string::npos)
  {
    return false;
  }
  std::size_t end = file.find("</title>");
  if (end == std::string::npos)
  {
    return false;
  }
  begin += std::string("<title>").size(); // begin指向<title>后面第一个字符
  if (begin > end)
  {
    return false;
  }
  *title = file.substr(begin, end - begin);
  return true;
}

//标签都要去掉
static bool ParseContent(const std::string &file, std::string *content)
{
  // 去标签,状态机
  enum status
  {
    LABLE,
    CONTENT
  };

  enum status s = LABLE; // 默认为LABLE状态
  for (char c : file) //以字符方式遍历file
  {
    switch (s)
    {
    case LABLE:
      if (c == '>') // 碰到>就意味着标签处理完毕
        s = CONTENT;
      break;
    case CONTENT:
      if (c == '<')  //碰到<就意味着内容处理完毕
        s = LABLE;
      else
      {
        // 不保留原始文件的\n, \n用来做html解析之后的文本分割符
        if (c == '\n')
          c = ' ';
        content->push_back(c);
      }
      break;
    default:
      break;
    }
  }
  return true;
}


static bool ParseUrl(const std::string &file_path, std::string *url)
{
  std::string url_head = "https://www.boost.org/doc/libs/1_83_0/doc/html";
  std::string url_tail = file_path.substr(src_path.size()); //src_path = "data/input"  tail--只要accumulators.html
  *url = url_head + url_tail;
  return true;
}

// static void ShowDoc(const DocInfo_t &doc)
// {
//   std::cout << "title: " << doc.title << std::endl;
//   std::cout << "content: " << doc.content << std::endl;
//   std::cout << "url: " << doc.url << std::endl;
// }

bool ParseHtml(const std::vector<std::string> &files_list, std::vector<DocInfo_t> *results)
{
  for (const std::string &file : files_list)
  {
    std::string result;
    // 读文件
    if (!ns_util::FileUtil::ReadFile(file, &result))
    {
      continue;
    }

    DocInfo_t doc;
    // 解析文件,提取title
    if (!ParseTitle(result, &doc.title))
    {
      continue;
    }
    // 解析文件,提取continue--去标签
    if (!ParseContent(result, &doc.content))
    {
      continue;
    }
    // 解析文件路径,构建url
    if (!ParseUrl(file, &doc.url))
    {
      continue;
    }

    // 完成解析任务,解析结果保存在doc中
    results->push_back(std::move(doc)); // 减少拷贝

    // Debug
    //  ShowDoc(doc);
    //  break;
  }
  return true;
}


#define SEP '\3'
//解析完的文件保存在output中
bool SaveHtml(const std::vector<DocInfo_t> &results, const std::string &output)
{

  std::ofstream out(output, std::ios::out | std::ios::binary); // 二进制写入--写入什么文档保存就是什么
  if (!out.is_open())
  {
    std::cerr << "open " << output << "failed" << std::endl;
    return false;
  }
  //文件内容写入
  //title\3content\3url \n  title\3content\3url \n ....
  //方便getline(ifsream,line)直接获取文档全部内容 title\3content\3url(getline以\n结束)  
  for (auto &item : results)
  {
    std::string out_string;
    out_string = item.title;
    out_string += SEP;
    out_string += item.content;
    out_string += SEP;
    out_string += item.url;
    out_string += '\n'; // 文档和文档之间的分隔

    out.write(out_string.c_str(), out_string.size());
  }
  out.close();
  return true;
}

